/**
 * @author n0tnull
 *
 */
package fr.gadcparis.envieparisienne;

import java.util.ArrayList;
import java.util.List;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.OverlayItem;
import com.readystatesoftware.mapviewballoons.BalloonItemizedOverlay;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import fr.gadcparis.envieparisienne.model.Hit;
import greendroid.app.GDMapActivity;
import fr.gadcparis.envieparisienne.model.OpenDataClient;
import greendroid.widget.ActionBar;
import greendroid.widget.ActionBarItem;
import greendroid.widget.ActionBarItem.Type;

public class AroundMeActivity extends GDMapActivity {

	private MapView gMap;
	private Context context;
	private MapController myMapController;
	private LocationManager myLocationManager;
	private LocationListener myLocationListener;
	private MyLocationOverlay myLocationOverlay;
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	private Location loc;
	private GetData gd;
	private boolean searchingStatus = false;
	private Bundle b;
	private int category_wanted;
	private ArrayList<Hit> restList;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		category_wanted = -99;
		this.context = this;
		ActionBar aBar = getActionBar();
		aBar.setTitle(this.getString(R.string.map));
		setActionBarContentView(R.layout.mapview);
		addActionBarItem(Type.LocateMyself);	

		gMap = (MapView) this.findViewById(R.id.mapview);
		gMap.setBuiltInZoomControls(true);

		myMapController = gMap.getController();
		myMapController.setZoom(17); //Fixed Zoom Level

		gd = new GetData();
		b = this.getIntent().getExtras();

		if( b != null){
			Log.i("AroundMe","Bundle received !");
			category_wanted = b.getInt(context.getString(R.string.category_needed));
			if(category_wanted == OpenDataClient.HUNGER_CLIENT)
				restList = Singleton.getInstance().getMyList();
		}			

		myLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

		myLocationListener = new MyLocationListener();
		// create an overlay that shows our current location
		myLocationOverlay = new MyLocationOverlay(this, gMap);
	}

	private class GetData extends AsyncTask<Integer, Void, Void>{
		ProgressDialog pg;
		OpenDataClient client;
		BasicItemizedOverlay hunger, thirsty, pee, sex;
		boolean h,t,p,s;
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			pg = new ProgressDialog(context);
			pg.setMessage(context.getString(R.string.wait_msg));
			pg.show();
			hunger = new BasicItemizedOverlay( getResources().getDrawable(R.drawable.pin_trans) , gMap, context);
			pee = new BasicItemizedOverlay( getResources().getDrawable(R.drawable.pin_trans_blue) , gMap, context);
			thirsty = new BasicItemizedOverlay( getResources().getDrawable(R.drawable.pin_trans_green) , gMap, context);
			sex = new BasicItemizedOverlay( getResources().getDrawable(R.drawable.pin_trans_pink) , gMap, context);
			h = t = p = s = false;
		}

		@Override
		protected Void doInBackground(Integer... params) {
			Log.i("GetData","params = " + params[0]);

			if(params[0] != OpenDataClient.HUNGER_CLIENT){

				client = new OpenDataClient()
				.limit(10)
				.setTarget(params[0]);

				client.near(loc, 1000);

				for (int i = 0  ; i < client.count() ; i++ ) {
					Hit hit = client.getHit(i);
					if(hit.getCategory() == OpenDataClient.HUNGER_CLIENT){
						h = true;
						hunger.addHit(hit, new OverlayItem(hit.getGeoPoint(), hit.getName(), hit.getType()));
					} else if(hit.getCategory() == OpenDataClient.PEE_CLIENT){
						p = true;
						pee.addHit(hit, new OverlayItem(hit.getGeoPoint(), hit.getName(), hit.getType()));
					} else if(hit.getCategory() == OpenDataClient.THIRSTY_CLIENT){
						t = true;
						thirsty.addHit(hit, new OverlayItem(hit.getGeoPoint(), hit.getName(), hit.getType()));
					} else if(hit.getCategory() == OpenDataClient.SEX_CLIENT){
						s = true;
						sex.addHit(hit, new OverlayItem(hit.getGeoPoint(), hit.getName(), hit.getAddress()));
					}
					Log.i("TOTO", "Hit: " + hit.getName() + ": " +  hit.getAddress() + " " + hit.getLocation().getLatitude() + ", " + hit.getLocation().getLongitude() + " " + loc.distanceTo(hit.getLocation()));
				}
			} else {
				if(restList.size() > 0){
					h = true;
					for(Hit resto: restList){
						hunger.addHit(resto, new OverlayItem(resto.getGeoPoint(), resto.getName(), resto.getType()));
					}
				}
			}

			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			if (h) gMap.getOverlays().add(hunger);
			if (t) gMap.getOverlays().add(thirsty);
			if (p) gMap.getOverlays().add(pee);
			if (s) gMap.getOverlays().add(sex);
			gMap.getOverlays().add(myLocationOverlay);
			gMap.postInvalidate();
			pg.dismiss();
			Log.i("TOTO","Fin d'Async");
			// TODO Auto-generated method stub
			super.onPostExecute(result);
		}

	}



	private class BasicItemizedOverlay extends BalloonItemizedOverlay<OverlayItem> {

		private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
		private List<Hit> hits = new ArrayList<Hit>();
		private Context context;

		public BasicItemizedOverlay(Drawable defaultMarker, MapView mapView, Context context) {
			super(boundCenter(defaultMarker), mapView);
			this.context = context;
		}

		@Override
		protected OverlayItem createItem(int i) {
			return mOverlays.get(i);
		}

		public void addOverlay(OverlayItem overlay){
			mOverlays.add(overlay);
			populate();
		}

		public void addHit(Hit hit, OverlayItem overlay){
			hits.add(hit);
			addOverlay(overlay);
		}

		@Override
		public int size() {
			return mOverlays.size();
		}

		@Override
		protected boolean onBalloonTap(int index, OverlayItem item) {
			Intent intent = new Intent(context, DetailsItemActivity.class);
			intent.putExtra("hit", hits.get(index));
			startActivity(intent);
			return super.onBalloonTap(index, item);
		}

	}

	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean onHandleActionBarItemClick(ActionBarItem item, int position) {
		if(loc != null){
			GeoPoint initGeoPoint = new GeoPoint((int)(loc.getLatitude()*1000000),(int)(loc.getLongitude()*1000000));
			CenterLocation(initGeoPoint);
		} // TODO: Faire le dialog d'erreur !
		return true;
	}

	private void CenterLocation(GeoPoint centerGeoPoint)
	{
		myMapController.animateTo(centerGeoPoint);
	}


	/** Determines whether one Location reading is better than the current Location fix
	 * @param location  The new Location that you want to evaluate
	 * @param currentBestLocation  The current Location fix, to which you want to compare the new one
	 */
	protected boolean isBetterLocation(Location location, Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
			return true;
		}
		return false;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}


	private final class MyLocationListener implements LocationListener {

		public void onLocationChanged(Location locFromGps) {
			if(isBetterLocation(locFromGps, loc)){
				loc = locFromGps;
				if (!searchingStatus) {
					Log.i("AroundMe","Category = " + category_wanted);
					searchingStatus = true;
					if( category_wanted == -99){
						gd.execute(OpenDataClient.ALL_CLIENT);
					} else {
						gd.execute(category_wanted);
					}
				}
				GeoPoint initGeoPoint = new GeoPoint((int)(loc.getLatitude()*1000000),(int)(loc.getLongitude()*1000000));
				CenterLocation(initGeoPoint);
			}
			// called when the listener is notified with a location update from the GPS
		}

		public void onProviderDisabled(String provider) {
			// called when the GPS provider is turned off (user turning off the GPS on the phone)
		}

		public void onProviderEnabled(String provider) {
			// called when the GPS provider is turned on (user turning on the GPS on the phone)
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
			// called when the status of the GPS provider changes
		}
	}

	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		myLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,myLocationListener);
		myLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0,myLocationListener);

		myLocationOverlay.enableMyLocation();
		loc = myLocationOverlay.getLastFix();
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		myLocationOverlay.disableMyLocation();
		myLocationManager.removeUpdates(myLocationListener);
	}

	@Override
	protected void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
	}

}
